package com.wqnmdb.im.service.mongo;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * @ClassName: MongoPage
 * @Description: mongo分页鸡类
 * @Author: 王欣
 * @CreateDate: 2018-4-18 16:13
 * @Version: 1.0
 */
public class MongoPage<T> {

    /**
     * 总页数
     */
    protected int pages = 1;

    /**
     * 分页参数-页码
     */
    protected int pageNo = 1;

    /**
     * 分页参数-每页记录数
     */
    protected int pageSize = 10;

    /**
     * 自动计算总记录数 默认为false.
     */
    protected boolean autoCount = false;

    /**
     * 返回结果
     */
    protected Collection<T> result = new ArrayList<T>();
    /**
     * 总记录数
     */
    protected long totalCount = -1;
    /** 大翻页一半的页数 */
    protected int tuneSize = 5;

    /**
     * 构造函数
     */
    public MongoPage() {
    }

    /**
     * 构造函数
     * @param pageSize
     */
    public MongoPage(int pageSize) {
        this.pageSize = pageSize;
    }

    //-- 分页参数访问函数 --//
    /**
     * 获得当前页的页号,序号从1开始,默认为1.
     */
    public int getPageNo() {
        return pageNo;
    }

    /**
     * 设置当前页的页号,序号从1开始,低于1时自动调整为1.
     */
    public void setPageNo(final int pageNo) {
        this.pageNo = pageNo;

        if (pageNo < 1) {
            this.pageNo = 1;
        }
    }

    /**
     * 返回Page对象自身的setPageNo函数,可用于连续设置。
     */
    public MongoPage<T> pageNo(final int thePageNo) {
        setPageNo(thePageNo);
        return this;
    }


    public int getPages() {
        return pages;
    }

    public void setPages(int pages) {
        this.pages = pages;
    }

    /**
     * 获得每页的记录数量, 默认为-1.
     */
    public int getPageSize() {
        return pageSize;
    }

    /**
     * 设置每页的记录数量.
     */
    public void setPageSize(final int pageSize) {
        this.pageSize = pageSize;
    }

    /**
     * 返回Page对象自身的setPageSize函数,可用于连续设置。
     */
    public MongoPage<T> pageSize(final int thePageSize) {
        setPageSize(thePageSize);
        return this;
    }

    /**
     * 根据pageNo和pageSize计算当前页第一条记录在总结果集中的位置,序号从1开始.
     */
    public int getFirst() {
        return ((pageNo - 1) * pageSize);
    }

    /**
     * 获得查询对象时是否先自动执行count查询获取总记录数, 默认为false.
     */
    public boolean isAutoCount() {
        return autoCount;
    }

    /**
     * 设置查询对象时是否自动先执行count查询获取总记录数.
     */
    public void setAutoCount(final boolean autoCount) {
        this.autoCount = autoCount;
    }

    /**
     * 返回Page对象自身的setAutoCount函数,可用于连续设置。
     */
    public MongoPage<T> autoCount(final boolean theAutoCount) {
        setAutoCount(theAutoCount);
        return this;
    }

    //-- 访问查询结果函数 --//

    /**
     * 获得页内的记录列表.
     */
    public Collection<T> getResult() {
        return result;
    }

    /**
     * 设置页内的记录列表.
     */
    public void setResult(final Collection<T> result) {
        this.result = result;
    }

    /**
     * 获得总记录数, 默认值为-1.
     */
    public long getTotalCount() {
        return totalCount;
    }

    /**
     * 设置总记录数.
     */
    public void setTotalCount(final long totalCount) {
        this.totalCount = totalCount;
    }

    /**
     * 根据pageSize与totalCount计算总页数, 默认值为-1.
     */
    public long getTotalPages() {
        if (totalCount < 0) {
            return -1;
        }

        int count = (int)totalCount / pageSize;
        if (totalCount % pageSize > 0) {
            count++;
        }
        return count;
    }

    /**
     * 是否还有下一页.
     */
    public boolean isHasNext() {
        return (pageNo + 1 <= getTotalPages());
    }

    /**
     * 取得下页的页号, 序号从1开始.
     * 当前页为尾页时仍返回尾页序号.
     */
    public int getNextPage() {
        if (isHasNext()) {
            return pageNo + 1;
        } else {
            return pageNo;
        }
    }

    /**
     * 是否还有上一页.
     */
    public boolean isHasPre() {
        return (pageNo - 1 >= 1);
    }

    /**
     * 取得上页的页号, 序号从1开始.
     * 当前页为首页时返回首页序号.
     */
    public int getPrePage() {
        if (isHasPre()) {
            return pageNo - 1;
        } else {
            return pageNo;
        }
    }

    /**
     * 模仿阿里巴巴的分页效果。
     * 描述：根据page对象中得当前页和总页数，计算出来以当前页为中心前后各偏移4个数位的pages列表。
     * example1:如果当前页为6,该方法返回的为{2,3,4,5,6,7,8,9,10},依次类推
     * example2:如果当前页为1,该方法返回的为{1,2,3,4,5,6,7,8,9}.
     * 目前好像还有些bug，需要进一步优化。
     * @return
     * @author 王欣
     */
    public List<String> getPageList(){
        List<String> pages = new ArrayList<String>();
        //偏移量
        int correction = 0;
        int four = 4;
        int five = 5;
        for(int i=four;i>0;i--){
            if((pageNo-i)>0) {
                pages.add(String.valueOf(pageNo-i));
            }
            else {
                correction++;
            }
        }
        pages.add(String.valueOf(pageNo));
        for(int i=1;i<five+correction;i++){
            if((pageNo+i)<=getTotalPages()) {
                pages.add(String.valueOf(pageNo+i));
            }
        }
        return pages;
    }

    /**
     * 得到翻页起始页
     *
     * @return
     */
    public int getStartTuneNo() {
        int start = pageNo - tuneSize >0 ? pageNo - tuneSize : 1;
        int end = (int) (getTotalPages() - (pageNo + tuneSize) > 0 ? pageNo + tuneSize:getTotalPages());
        // 已经够页数
        int two = 2;
        if (end - start >= two * tuneSize) {
            return start;
        }
        // 需要补齐的条数
        int x = 2 * tuneSize + 1 - (end - start +1) ;
        // 从start补齐
        if (start>1) {
            return start - x>1?start-x:1;
        }
        return start;
    }

    /**
     * 得到翻页结束页
     *
     * @return
     */
    public int getEndTuneNo() {
        int start = pageNo - tuneSize >0 ? pageNo - tuneSize : 1;
        int end = (int) (getTotalPages() - (pageNo + tuneSize) > 0 ? pageNo + tuneSize:getTotalPages());
        // 已经够页数
        int two = 2;
        if (end - start >= two * tuneSize) {
            return end;
        }
        // 需要补齐的条数
        int x = 2 * tuneSize + 1 - (end - start +1) ;
        // 从end补齐
        if (end<getTotalPages()) {
            return (int)  (end + x > getTotalPages() ? getTotalPages():end+x);
        }
        return end;
    }
}